//------------------------------------------------------------------------------------------------- 
// <copyright file="Serialization.cs" company="Collaboris">
// Copyright (c) Collaboris.  All rights reserved.
// </copyright>
// <summary>Defines the SerialisationHelper type.</summary>
//-------------------------------------------------------------------------------------------------
namespace Collaboris.Utils
{
    using System;
    using System.IO;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;

    /// <summary>
    /// Provides helper classes for Xml Serialization
    /// </summary>
    public static class SerialisationHelper
    {
        /// <summary>
        /// Serializes the specified obj.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <returns></returns>
        public static string Serialize<T>(T obj)
        {
            using (StringWriter sw = new StringWriter())
            {
                string xml;
                System.Xml.Serialization.XmlSerializer xs;

                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");

                XmlSerializer serializer = new XmlSerializer(obj.GetType());                
                XmlWriter writer = new XmlTextWriterFormattedNoDeclaration(sw);
                serializer.Serialize(writer, obj, ns);

                xml = sw.ToString();

                return xml;
            }
        }        
        
        /*
        /// <summary>
        /// Serializes the specified obj.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <returns></returns>
        public static string Serialize(Object obj)
        {
            if (obj == null)
                ValidationHelper.VerifyObjectArgument(obj, "obj");

            using (StringWriter sw = new StringWriter())
            {
                string xml;
                System.Xml.Serialization.XmlSerializer xs;

                xs = new System.Xml.Serialization.XmlSerializer(obj.GetType());
                xs.Serialize(sw, obj);
                xml = sw.ToString();

                return xml;
            }
        }
        */

        /// <summary>
        /// Deserializes the specified XML.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static T Deserialize<T>(string xml)
        {
            using (XmlTextReader xtr = new XmlTextReader(new StringReader(xml)))
            {
                T obj;
                
                System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(T));
                if (!xs.CanDeserialize(xtr))
                    throw new XmlException(string.Format("Xml is not deserializable to {0}", typeof(T)));
                obj = (T)xs.Deserialize(xtr);

                return obj;
            }            
        }

        /// <summary>
        /// Deserializes the specified XML.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static object Deserialize(string typeStr, string xml, bool includeNameSpaces)
        {
            using (XmlTextReader xtr = new XmlTextReader(new StringReader(xml)))
            {
                xtr.Namespaces = includeNameSpaces;
                Type type = Type.GetType(typeStr);

                System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(type);
                if (!xs.CanDeserialize(xtr))
                    throw new XmlException(string.Format("Xml is not deserializable to {0}", type));
                return xs.Deserialize(xtr);
            }
        }

        public static object Deserialize(string typeStr, string xml)
        {
            return Deserialize(typeStr, xml, true);
        }


        /// <summary>
        /// Deserializes the specified XML by attempting to read the Type string.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static object Deserialize(string xml)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            if (doc.DocumentElement != null)
            {
                string typeValue = doc.DocumentElement.Attributes["type"].Value;
                if (string.IsNullOrEmpty(typeValue))
                    return null;
                else
                {
                    return Deserialize(typeValue, xml, false);
                }
            }
            return null;
        }

        /*
        /// <summary>
        /// Deserializes the specified type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static object Deserialize(Type type, string xml)
        {
            object obj;
            XmlTextReader xtr = null;
            try
            {
                xtr = new XmlTextReader(new StringReader(xml));
                System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(type);
                if (!xs.CanDeserialize(xtr))
                    throw new XmlException(string.Format("Xml is not deserializable to {0}", type));
                obj = xs.Deserialize(xtr);
            }
            finally
            {
                if (xtr != null)
                    xtr.Close();
            }
            return obj;
        }
        */

        /*
        /// <summary>
        /// Serializes to file.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <param name="filePath">The file path.</param>
        public static void SerializeToFile(Object obj, string filePath)
        {
            StreamWriter sw = null;
            try
            {
                sw = new StreamWriter(filePath);
                System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(obj.GetType());
                xs.Serialize(sw, obj);
            }
            finally
            {
                if (sw != null)
                    sw.Close();
            }
        }
        */

        /// <summary>
        /// Serializes to file.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <param name="filePath">The file path.</param>
        public static void SerializeToFile<T>(T obj, string filePath)
        {           
            using (StreamWriter sw = new StreamWriter(filePath))
            {                
                System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(T));
                xs.Serialize(sw, obj);                
            }
        }

        /*
        /// <summary>
        /// Deserializes from file.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="type" />
        /// <returns>
        /// </returns>
        public static object DeserializeFromFile(Type type, string filePath)
        {
            Object obj;
            StreamReader sr = null;
            try
            {
                sr = new StreamReader(filePath);
                System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(type);
                obj = xs.Deserialize(sr);
            }
            finally
            {
                if (sr != null)
                    sr.Close();
            }
            return obj;
        }*/

        /// <summary>
        /// Deserializes from file.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath">The file path.</param>
        /// <returns></returns>
        public static T DeserializeFromFile<T>(string filePath)
        {

            using (StreamReader sr = new StreamReader(filePath))
            {
                T obj;
                
                System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(T));
                obj = (T)xs.Deserialize(sr);

                return obj;
            }            
        }

        //Usage...
        ////Serialization:
        //MySerializableObject obj = new MySerializableObject();
        //string xml = IFXplus.Serialization.SerialisationHelper.Serialize(obj);

        //// Deserialization:
        //MySerializableObject obj2 = IFXplus.Serialization.SerialisationHelper.Deserialize<MySerializableObject>(xml); 

        /*
        public static string Serialize<T>(T obj)
        {
            try
            {
                MemoryStream memoryStream = new MemoryStream();
                using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8))
                {
                    System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
                    xmlSerializer.Serialize(xmlTextWriter, obj);
                    memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
                }
                return ByteArrayToString(Encoding.UTF8, memoryStream.ToArray());
            }
            catch
            {
                return string.Empty;
            }
        }
        */

        private static Byte[] StringToByteArray(Encoding encoding, string xml)
        {
            return encoding.GetBytes(xml);
        }

        private static string ByteArrayToString(Encoding encoding, byte[] byteArray)
        {
            return encoding.GetString(byteArray);
        }


    }

    public class XmlTextWriterFormattedNoDeclaration : System.Xml.XmlTextWriter
    {
        public XmlTextWriterFormattedNoDeclaration(System.IO.TextWriter w)
            : base(w)
        {
            Formatting = System.Xml.Formatting.Indented;
        }

        public override void WriteStartDocument() { } // suppress
    }
}